import { GraphConfigData } from "@logicflow/core";
import MyContext from "./MyContext";
import ELNode from "./type/ELNode";
import { ELType, GroupType } from "./type/ELType";
import Queue from "./type/Queue";
interface SingleNodeParseConfig {
    targetNode?: ELNode           // 遇到这个节点就终止
}

export default class MyParse {
    private logicFlow: GraphConfigData;

    private context: MyContext;

    constructor(logicFlow: GraphConfigData) {
        this.logicFlow = logicFlow;
        this.context = new MyContext();
        this.context.init(logicFlow);
    }

    public parse(): ELNode {
        const startId = this.context.startId;
        const node = new ELNode();
        node.id = startId;
        this.parseThenChain(node);
        return this.context.pop();
    }

    /**
     * 解析一条链
     * @param node 这条链的开始节点 
     * @param defaultData 链前面的一些节点，这些节点是并行的
     * @returns 
     */
    private parseThenChain(node: ELNode, targetNode?: ELNode, defaultData?: ELNode, id: string = ""): ELNode {
        this.context.createStackEnv({ type: ELType.THEN, aliasId: id } as ELNode);

        if (defaultData) {
            this.context.push(defaultData)
        }

        this.parseSingleNode(node, { targetNode });
        return this.context.quitStackEnv();
    }

    /**
     * 分析单个的then节点
     *
     * @param node    节点id
     * @param isStart 是否是then链的起点
     * @returns
     */
    private parseSingleNode(node: ELNode, config: SingleNodeParseConfig) {
        const id = node.id;
        const inNum = this.context.getSourceNum(node);
        const outNum = this.context.getEndNum(node);
        const newConfig: SingleNodeParseConfig = {
            targetNode: config.targetNode
        }

        if (this.context.isEnd(id)) {
            this.context.setStackEndPoint(node);
            return null;
        }
        if (config.targetNode && config.targetNode.id === node.id) {
            this.context.setStackEndPoint(node);
            return null;
        }

        // 虚拟节点不展示,其他节点入栈
        if (!this.context.isStart(id)) this.context.push(node);

        //先分析特殊节点
        if (ELType.IF === node.type) {
            const next = this.parseIF(this.context.pop());
            return this.parseSingleNode(next, newConfig);
        }
        if (ELType.SWITCH === node.type) {
            const next = this.parseWhich(this.context.pop());
            return this.parseSingleNode(next, newConfig);
        }
        //需要考虑与或非表达式作为if起点的情况
        if (ELType.GROUP === node.type) {
            let next = this.parseGroup(this.context.pop());
            if (node.groupType === GroupType.LOGIC && outNum > 0 && !this.context.isEnd(this.context.getEndList(node)[0].id)) {
                const logicNode = this.context.pop();
                next = this.parseIF(logicNode);
            }
            return this.parseSingleNode(next, newConfig);
        }

        //普通节点
        if (outNum === 1) {
            return this.parseSingleNode(this.context.getEndList(node)[0], newConfig);
        }
        //否则为when节点
        const next = this.parseWhenChain(node);
        return this.parseSingleNode(next, newConfig);
    }


    /**
     * 将各个分支依次压入栈中
     *
     * @param node 分支收束的节点
     */
    private parseBranch(node: ELNode): ELNode {
        const follows = this.context.getEndList(node);

        let next = this.getBranchEnd(node) as ELNode

        follows.forEach(start => {
            if (start.id == next.id) { // 不解析空链
                return
            }
            this.parseThenChain(start, next, undefined, node.type === ELType.SWITCH ? start.comingEdgeText : "");
            //如果是WITCH节点，可以再边上添加id说明
        })

        return next;
    }

    private parseIF(node: ELNode) {
        debugger;
        const typenode = new ELNode()
        typenode.type = ELType.IF;
        this.context.createStackEnv(typenode);

        if (node.type === ELType.IF) node.type = ELType.ID;
        this.context.push(node);
        //if节点必然有两个分支，但是可能有undefined
        const ends = this.context.getEndList(node).filter(n => !!n);
        const outNum = ends.length;

        // 当if节点分支数为1，必须在末尾
        if (outNum == 1) {
            let child: ELNode;
            let end: ELNode;
            try {
                child = ends[0];
                end = this.context.endPoints[child.id][0];
                if (!this.context.isEnd(end.id)) throw new Error();
            } catch (err) {
                throw new Error("IF 判断节点的分支数必须为2");
            }

            this.context.push(child);
            this.context.setStackEndPoint(end);
            return this.context.quitStackEnv();
        }
        if (outNum != 2) throw new Error("IF 判断节点的分支数必须为2");
        const end = this.parseBranch(node);
        this.context.setStackEndPoint(end);
        return this.context.quitStackEnv();
    }

    /**
     * 解析Switch节点，这里不应该使用parseBranch，每一个后继节点都应该看成单独的一条链
     * @param node type为Switch的节点
     * @returns 
     */
    private parseWhich(node: ELNode): ELNode {
        const follows = this.context.getEndList(node);
        const outNum = follows.length;
        if (outNum <= 1) throw new Error("WHICH 分支节点的分支数必须大于1");
        // 下面开始正式的解析
        this.context.createStackEnv(node);
        const next = this.parseBranch(node);
        this.context.setStackEndPoint(next);
        return this.context.quitStackEnv();
    }

    /**
     * 不包含提前收束节点的并行解析方法
     * @param follows 所有开始节点
     * @param end 收束节点
     * @returns 
     */
    private parseWhenBase(follows: ELNode[], end: ELNode, datas: ELNode[]): ELNode {
        this.context.createStackEnv({ type: ELType.WHEN } as ELNode);
        follows.forEach((s, index) => {
            if (s.id == end.id) { // 不解析空链
                return
            }
            this.parseThenChain(s, end, datas[index]);
        })
        this.context.quitStackEnv();
        return this.context.pop();
    }

    /**
     * 解析When节点
     *
     * @param node when的开始节点
     * @returns when的结束节点，便于继续分析
     */
    private parseWhenChain(node: ELNode): ELNode {
        this.context.createStackEnv({ type: ELType.WHEN } as ELNode);
        const ends = this.context.getEndList(node)

        const next = this.getBranchEnd(node) as ELNode
        const endNodes = this.getBranchEnd(node, next) as Record<string, number[]>

        const endMap: Record<string, string> = {}    //开始节点对应的收束节点
        const endData: Record<string, ELNode> = {} // 节点对应的数据

        // 先将对象的键值对转换为数组并按照 number[] 的长度从小到大排序
        const sortedEntries = Object.entries(endNodes)
            .sort(([, a], [, b]) => a.length - b.length);

        // 遍历排序后的数组
        sortedEntries.forEach(([endId, value]) => {
            const endNode = this.context.getNodeById(endId)
            if (value.length == 1) return // 长度为1说明不是收束节点

            const follows: any[] = []
            value.forEach(index => {
                const node = ends[index]
                debugger
                if (endMap[node.id]) {
                    follows.push(endMap[node.id])
                } else {
                    follows.push(node.id)
                }
            })
            value.forEach(index => {
                const node = ends[index]
                endMap[node.id] = endId
            })



            const fs = Array.from(new Set(follows)).map(nodeId => this.context.getNodeById(nodeId))
            debugger
            const data = this.parseWhenBase(fs, endNode, fs.map(f => endData[f.id]))
            endData[endId] = data

        });

        this.context.push(endData[next.id])

        this.context.setStackEndPoint(next);
        return this.context.quitStackEnv();
    }


    /**
     * 解析group
     * @param node 
     */
    private parseGroup(node: ELNode): ELNode {
        const ends = this.context.getEndList(node);

        let res: ELNode;
        let toEnd: boolean = true;//是否直接连接到end，即没有后继节点

        ends.forEach(end => {
            if (end.comingEdgeText) {
                this.parseThenChain(end);
                const then = this.context.elStack.pop();
                switch (end.comingEdgeText) {
                    case "START":
                        node.startNode = then.child[0];
                        break;
                    case "BREAK":
                        node.breakNode = then.child[0];
                        break;
                    case "EXCEPTION":
                        node.exceptionNode = then.child[0];
                        break;
                }
            } else {
                res = end;
                toEnd = false;
            }
        })
        this.context.elStack.push(node);
        if (toEnd) {
            return new ELNode(this.context.endId)
        }
        return res!;
    }

    /**
     * 获取分支的结束节点 ,原理就是获取每个分支都能走到的节点
     * 用于switch,if等的解析,endNode 指定结束节点
     */
    private getBranchEnd(node: ELNode, endNode?: ELNode): ELNode | Record<string, number[]> {
        const endNodes = {}
        //分支起点的出度，用于判断何时结束
        let outNum = this.context.getEndNum(node);
        // 获取后继节点id列表
        const nodes_id = this.context.getEndList(node).map(n => n.id)
        // 节点的访问次数
        const visited_count: Record<string, number> = {}
        while (true) {
            for (let i = 0; i < nodes_id.length; i++) {
                const id = nodes_id[i]
                if (!id) continue
                const n = this.context.getNodeById(id)
                //更新访问次数
                if (!visited_count[n.id]) visited_count[n.id] = 0
                visited_count[n.id]++

                //记录每个节点对应的开始节点，用于WHEN解析
                if (!endNodes[n.id]) endNodes[n.id] = []
                endNodes[n.id].push(i)

                //访问次数达标，返回该节点
                if (visited_count[n.id] === outNum) {
                    // 如果是选择节点并且有空链，就将next推后
                    if (node.type === ELType.SWITCH && this.context.getEndList(node).some(x => x.id === n.id)) {
                        return this.getBranchEnd(n)
                    }
                    if (endNode) return endNodes
                    return n
                }


                if (this.context.isEnd(n.id) || n.id === endNode?.id) {//结束节点不再向后或者到达指定的结束节点
                    nodes_id[i] = ""
                } else if (this.context.getEndNum(n) > 1) { //递归解析
                    nodes_id[i] = (this.getBranchEnd(n) as ELNode).id
                } else { // 修改为下一个节点
                    nodes_id[i] = this.context.getEndList(n)[0].id
                }
            }
        }
    }
}